<template>
  <div
    :class="['segmented', { 'is-block': block, 'is-disabled': disabled }]"
    :style="controlStyle"
    :id="id"
    :name="name"
    :aria-label="ariaLabel"
    ref="segmentedRef"
  >
    <!-- 滑动指示器 -->
    <div
      class="segmented-slider"
      :style="sliderStyle"
    ></div>
    <div
      v-for="(option, index) in options"
      :key="index"
      :class="[
        'segmented-item',
        {
          'is-active': isActive(option),
          'is-disabled': isDisabled(option),
        },
      ]"
      :style="itemStyle"
      :ref="(el) => setItemRef(el, index)"
      @click="handleClick(option)"
    >
      <span class="segmented-item-label">{{ getLabel(option) }}</span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, nextTick, type CSSProperties, type ComponentPublicInstance } from "vue";

defineOptions({
  name: "Segmented",
});

export interface SegmentedOption {
  [key: string]: any;
}

export interface SegmentedProps {
  modelValue?: string | number | boolean;
  options: SegmentedOption[];
  props?: {
    value?: string;
    label?: string;
    disabled?: string;
  };
  block?: boolean;
  disabled?: boolean;
  name?: string;
  id?: string;
  ariaLabel?: string;
  direction?: "horizontal" | "vertical";
}

const props = withDefaults(defineProps<SegmentedProps>(), {
  modelValue: undefined,
  options: () => [],
  props: () => ({
    value: "value",
    label: "label",
    disabled: "disabled",
  }),
  block: true,
  disabled: false,
  name: undefined,
  id: undefined,
  ariaLabel: undefined,
  direction: "horizontal",
});

const emit = defineEmits<{
  (e: "update:modelValue", value: string | number | boolean): void;
  (e: "change", value: string | number | boolean, option: SegmentedOption): void;
}>();

const segmentedRef = ref<HTMLElement | null>(null);
const itemRefs = ref<(HTMLElement | null)[]>([]);

const setItemRef = (el: Element | ComponentPublicInstance | null, index: number) => {
  if (el && el instanceof HTMLElement) {
    itemRefs.value[index] = el;
  } else if (el && '$el' in el && el.$el instanceof HTMLElement) {
    itemRefs.value[index] = el.$el;
  } else {
    itemRefs.value[index] = null;
  }
};

const controlStyle = computed<CSSProperties>(() => {
  return {
    flexDirection: props.direction === "vertical" ? "column" : "row",
  };
});

const itemStyle = computed<CSSProperties>(() => {
  return {};
});

const getValue = (option: SegmentedOption): string | number | boolean => {
  return option[props.props?.value || "value"];
};

const getLabel = (option: SegmentedOption): string => {
  const label = option[props.props?.label || "label"];
  return typeof label === "string" ? label : String(label);
};

const isDisabled = (option: SegmentedOption): boolean => {
  if (props.disabled) return true;
  const disabled = option[props.props?.disabled || "disabled"];
  return Boolean(disabled);
};

const isActive = (option: SegmentedOption): boolean => {
  const value = getValue(option);
  return value === props.modelValue;
};

// 计算滑动指示器的样式
const sliderStyle = computed<CSSProperties>(() => {
  const activeIndex = props.options.findIndex((option) => isActive(option));
  if (activeIndex === -1 || !segmentedRef.value || !itemRefs.value[activeIndex]) {
    return {
      opacity: 0,
    };
  }

  const container = segmentedRef.value;
  const activeItem = itemRefs.value[activeIndex];
  
  if (!activeItem) {
    return {
      opacity: 0,
    };
  }

  const containerRect = container.getBoundingClientRect();
  const itemRect = activeItem.getBoundingClientRect();

  if (props.direction === "vertical") {
    return {
      top: `${itemRect.top - containerRect.top + 2}px`,
      left: "2px",
      width: `calc(100% - 4px)`,
      height: `${activeItem.offsetHeight - 4}px`,
      opacity: 1,
    };
  } else {
    return {
      left: `${itemRect.left - containerRect.left + 2}px`,
      top: "2px",
      width: `${activeItem.offsetWidth - 4}px`,
      height: `calc(100% - 4px)`,
      opacity: 1,
    };
  }
});

const handleClick = (option: SegmentedOption) => {
  if (isDisabled(option)) return;

  const value = getValue(option);
  emit("update:modelValue", value);
  emit("change", value, option);
};

// 监听 modelValue 变化，触发重新计算
watch(
  () => props.modelValue,
  () => {
    nextTick(() => {
      // 触发重新计算 sliderStyle
    });
  }
);
</script>

<style lang="scss" scoped>
.segmented {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: var(--segmented-control-padding, 2px);
  background-color: var(--segmented-control-background, #f0f0f0);
  border-radius: var(--segmented-control-border-radius, 6px);
  position: relative;

  &.is-block {
    width: 100%;
    display: flex;
  }

  &.is-disabled {
    opacity: var(--segmented-control-item-disabled-opacity, 0.5);
    cursor: var(--segmented-control-item-disabled-cursor, not-allowed);
    pointer-events: none;
  }
}

.segmented-slider {
  position: absolute;
  background-color: var(--editor-color-white);
  border-radius: calc(var(--segmented-control-border-radius, 6px) - 2px);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 1;
  pointer-events: none;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.segmented-item {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--segmented-control-item-padding, 0 12px);
  height: var(--segmented-control-height, 32px);
  font-size: var(--segmented-control-item-font-size, 14px);
  color: var(--segmented-control-item-color);
  background-color: transparent;
  border-radius: calc(var(--segmented-control-border-radius, 6px) - 2px);
  cursor: pointer;
  transition: color var(--segmented-control-item-transition, all 0.2s ease);
  user-select: none;
  white-space: nowrap;
  position: relative;
  z-index: 2;

  &:hover:not(.is-active):not(.is-disabled) {
    color: var(--editor-primary-color);
  }

  &.is-active {
    color: var(--editor-color-black);
    font-weight: 500;
  }

  &.is-disabled {
    opacity: var(--segmented-control-item-disabled-opacity, 0.5);
    cursor: var(--segmented-control-item-disabled-cursor, not-allowed);
    pointer-events: none;
  }
}

.segmented-item-label {
  display: inline-block;
  line-height: 1;
}

/* 暗色主题适配 */
[theme-mode="dark"] {
  .segmented-slider {
    background-color: var(--editor-primary-color);
  }

  .segmented-item.is-active {
    color: var(--editor-color-white);
  }
}
</style>
